package com.iclippi.server.model;

import java.util.Date;
import java.util.List;
import java.util.logging.Logger;

import javax.cache.CacheException;
import javax.jdo.PersistenceManager;
import javax.jdo.Query;
import javax.jdo.annotations.IdGeneratorStrategy;
import javax.jdo.annotations.IdentityType;
import javax.jdo.annotations.NotPersistent;
import javax.jdo.annotations.PersistenceCapable;
import javax.jdo.annotations.Persistent;
import javax.jdo.annotations.PrimaryKey;
import com.google.appengine.api.datastore.Text;
import com.iclippi.server.ClipboardServiceImpl;

@PersistenceCapable(identityType = IdentityType.APPLICATION)
public class Clipboard {

	@PrimaryKey
	@Persistent(valueStrategy = IdGeneratorStrategy.IDENTITY)
	private Long id;

	@Persistent
	private Long version = new Long(0);

	/**
	 * Length of name < 32. More characters will be trunked.
	 */
	@Persistent
	private String name;

	@Persistent
	private Date updateDate;

	@Persistent
	private Text content;

	@NotPersistent
	private static final Logger log = Logger
			.getLogger(ClipboardServiceImpl.class.getName());

	public Clipboard(String clipboardName) {
		log.info("Clipboard created - "+clipboardName);
		setName(clipboardName);
		this
				.updateClipboard("Welcome to clipboard named <b>"
						+ clipboardName
						+ "</b>!<br><br><span style='font-size:0.7em'>The Clippy team</span>");
	}

	public Clipboard(String clipboardName, String content) {
		setName(clipboardName);
		this.updateClipboard(content);
	}

	public String getContent() {
		return content.getValue();

	}

	private void setContent(String content) {
		updateDate = new Date();

		// Filter scripts, objecst, iframes, etc.
		String[] badWords = { "script", "object", "frame", "iframe", "embed",
				"applet" };

		for (String word : badWords) {
			content = content.replaceAll("(?i)\\<" + word, "[" + word);
			content = content.replaceAll("(?i)\\<\\/" + word, "[/" + word);
		}

		this.content = new Text(content);
	}

	public Long getId() {
		return id;
	}

	public String getName() {
		return name;
	}

	private void setName(String name) {
		this.name = Clipboard.getInternalName(name);
	}

	private static String getInternalName(String name) {
		return (name.length() > 31) ? name.substring(0, 32) : name;
	}

	public Long getVersion() {
		// Important, in case database contains older version of an entry
		if (version == null){
			log.warning("Version var is null - "+id);
			return new Long(0);
		}
		return version;
	}

	private void setVersion(Long version) {
		ClippyCache cache = null;
		try {
			cache = ClippyCache.getInstance();
			cache.setClipboardVersion(name, version);
		} catch (CacheException e) {
			log.warning("Can't initiate cache class - "+e.getMessage());
		}
		this.version = version;
	}

	private Long getNextVersion() {
		return getVersion() + 1;
	}

	public Date getUpdateDate() {
		return updateDate;
	}

	/**
	 * Update the clipboard content, and set the clipboard update time
	 * accordingly.
	 * 
	 * @param content
	 *            - can be HTML string.
	 */
	public void updateClipboard(String content) {
		PersistenceManager pm = PMF.get().getPersistenceManager();
		Long nextVersion;
		if (this.getId() == null) {
			this.setContent(content);
			nextVersion = getNextVersion();
			setVersion(nextVersion);
			try {
				pm.makePersistent(this);
			} finally {
				pm.close();
			}

		} else {
			try {
				Clipboard clipboard = pm.getObjectById(Clipboard.class, this
						.getId());
				clipboard.setContent(content);
				nextVersion = clipboard.getNextVersion();
				clipboard.setVersion(nextVersion);
				setVersion(nextVersion);
			} finally {
				pm.close();
			}
		}

	}

	/**
	 * Find the clipboard Id by it's name.<br>
	 * The method uses memCache, to cache the clipboard's ID
	 * 
	 * @param clipboardName
	 * @return Clipboard ID, if clipboardName exists. If doesn't exists, return
	 *         NULL
	 */
	@SuppressWarnings("unchecked")
	public static Long getClipboardId(String clipboardName) {
		String internalName = Clipboard.getInternalName(clipboardName);
		ClippyCache cache = null;
		try {
			cache = ClippyCache.getInstance();
			Long result = cache.getClipboardId(internalName);
			if (result != null)
				return result;
		} catch (CacheException e) {
			log.warning("Can't initiate cache class - "+e.getMessage());
		}

		PersistenceManager pm = PMF.get().getPersistenceManager();
		Query query = pm.newQuery(Clipboard.class);
		query.setFilter("name == nameParam");
		query.declareParameters("String nameParam");
		Long clipboardId = null;
		try {
			List<Clipboard> results = (List<Clipboard>) query
					.execute(internalName);
			if (!results.isEmpty())
				clipboardId = results.get(0).getId();
		} finally {
			query.closeAll();
			pm.close();
		}

		if (cache != null)
			cache.setClipboardId(internalName, clipboardId);
		return clipboardId;

	}

	/**
	 * Get clipboard object by its name. If doesn't found, create a new
	 * clipboard.<br>
	 * Return null only clipboardName is null.
	 * 
	 * @param clipboardName
	 * @return Clipboard
	 */
	public static Clipboard getClipboard(String clipboardName) {
		if (clipboardName == null)
			return null;
		Long id = getClipboardId(clipboardName);
		if (id == null)
			return new Clipboard(clipboardName);
		return getClipboard(id);
	}

	/**
	 * Get clipboard by its ID. If ID is null or no such ID, return null
	 * 
	 * @param id
	 * @return Clipboard
	 */
	public static Clipboard getClipboard(Long id) {
		if (id == null)
			return null;
		PersistenceManager pm = PMF.get().getPersistenceManager();
		Clipboard clipboard = pm.getObjectById(Clipboard.class, id);
		return clipboard;
	}

	public static Long getClipboardVersion(String clipboardName) {
		String internalName = Clipboard.getInternalName(clipboardName);
		ClippyCache cache = null;
		try {
			cache = ClippyCache.getInstance();
			Long result = cache.getClipboardVersion(internalName);
			if (result != null)
				return result;
		} catch (CacheException e) {
			log.warning("Can't initiate cache class - "+e.getMessage());
		}

		Clipboard clipboard = getClipboard(internalName);

		if (cache != null)
			cache.setClipboardVersion(internalName, clipboard.getVersion());
		return clipboard.getVersion();

	}

}
